﻿/*
 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
 @thinkgem 2013-8-1 添加标题，编辑链接名称。
 */

CKEDITOR.dialog.add('link', function (editor) {
    var plugin = CKEDITOR.plugins.link;
    // Handles the event when the "Target" selection box is changed.
    var targetChanged = function () {
        var dialog = this.getDialog(),
            popupFeatures = dialog.getContentElement('target', 'popupFeatures'),
            targetName = dialog.getContentElement('target', 'linkTargetName'),
            value = this.getValue();

        if (!popupFeatures || !targetName)
            return;

        popupFeatures = popupFeatures.getElement();
        popupFeatures.hide();
        targetName.setValue('');

        switch (value) {
            case 'frame' :
                targetName.setLabel(editor.lang.link.targetFrameName);
                targetName.getElement().show();
                break;
            case 'popup' :
                popupFeatures.show();
                targetName.setLabel(editor.lang.link.targetPopupName);
                targetName.getElement().show();
                break;
            default :
                targetName.setValue(value);
                targetName.getElement().hide();
                break;
        }

    };

    // Handles the event when the "Type" selection box is changed.
    var linkTypeChanged = function () {
        var dialog = this.getDialog(),
            partIds = ['urlOptions', 'anchorOptions', 'emailOptions'],
            typeValue = this.getValue(),
            uploadTab = dialog.definition.getContents('upload'),
            uploadInitiallyHidden = uploadTab && uploadTab.hidden;

        if (typeValue == 'url') {
            if (editor.config.linkShowTargetTab)
                dialog.showPage('target');
            if (!uploadInitiallyHidden)
                dialog.showPage('upload');
        }
        else {
            dialog.hidePage('target');
            if (!uploadInitiallyHidden)
                dialog.hidePage('upload');
        }

        for (var i = 0; i < partIds.length; i++) {
            var element = dialog.getContentElement('info', partIds[i]);
            if (!element)
                continue;

            element = element.getElement().getParent().getParent();
            if (partIds[i] == typeValue + 'Options')
                element.show();
            else
                element.hide();
        }

        dialog.layout();
    };

    // Loads the parameters in a selected link to the link dialog fields.
    var javascriptProtocolRegex = /^javascript:/,
        emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
        emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,
        emailBodyRegex = /body=([^;?:@&=$,\/]*)/,
        anchorRegex = /^#(.*)$/,
        urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,
        selectableTargets = /^(_(?:self|top|parent|blank))$/,
        encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/,
        functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/;

    var popupRegex =
        /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/;
    var popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/gi;

    var parseLink = function (editor, element) {
        var href = ( element && ( element.data('cke-saved-href') || element.getAttribute('href') ) ) || '',
            javascriptMatch,
            emailMatch,
            anchorMatch,
            urlMatch,
            retval = {};

        if (( javascriptMatch = href.match(javascriptProtocolRegex) )) {
            if (emailProtection == 'encode') {
                href = href.replace(encodedEmailLinkRegex,
                    function (match, protectedAddress, rest) {
                        return 'mailto:' +
                            String.fromCharCode.apply(String, protectedAddress.split(',')) +
                            ( rest && unescapeSingleQuote(rest) );
                    });
            }
            // Protected email link as function call.
            else if (emailProtection) {
                href.replace(functionCallProtectedEmailLinkRegex, function (match, funcName, funcArgs) {
                    if (funcName == compiledProtectionFunction.name) {
                        retval.type = 'email';
                        var email = retval.email = {};

                        var paramRegex = /[^,\s]+/g,
                            paramQuoteRegex = /(^')|('$)/g,
                            paramsMatch = funcArgs.match(paramRegex),
                            paramsMatchLength = paramsMatch.length,
                            paramName,
                            paramVal;

                        for (var i = 0; i < paramsMatchLength; i++) {
                            paramVal = decodeURIComponent(unescapeSingleQuote(paramsMatch[i].replace(paramQuoteRegex, '')));
                            paramName = compiledProtectionFunction.params[i].toLowerCase();
                            email[paramName] = paramVal;
                        }
                        email.address = [email.name, email.domain].join('@');
                    }
                });
            }
        }

        if (!retval.type) {
            if (( anchorMatch = href.match(anchorRegex) )) {
                retval.type = 'anchor';
                retval.anchor = {};
                retval.anchor.name = retval.anchor.id = anchorMatch[1];
            }
            // Protected email link as encoded string.
            else if (( emailMatch = href.match(emailRegex) )) {
                var subjectMatch = href.match(emailSubjectRegex),
                    bodyMatch = href.match(emailBodyRegex);

                retval.type = 'email';
                var email = ( retval.email = {} );
                email.address = emailMatch[1];
                subjectMatch && ( email.subject = decodeURIComponent(subjectMatch[1]) );
                bodyMatch && ( email.body = decodeURIComponent(bodyMatch[1]) );
            }
            // urlRegex matches empty strings, so need to check for href as well.
            else if (href && ( urlMatch = href.match(urlRegex) )) {
                retval.type = 'url';
                retval.url = {};
                retval.url.protocol = urlMatch[1];
                retval.url.url = urlMatch[2];
            }
            else
                retval.type = 'url';
        }

        // Load target and popup settings.
        if (element) {
            var target = element.getAttribute('target');
            retval.target = {};
            retval.adv = {};

            // IE BUG: target attribute is an empty string instead of null in IE if it's not set.
            if (!target) {
                var onclick = element.data('cke-pa-onclick') || element.getAttribute('onclick'),
                    onclickMatch = onclick && onclick.match(popupRegex);
                if (onclickMatch) {
                    retval.target.type = 'popup';
                    retval.target.name = onclickMatch[1];

                    var featureMatch;
                    while (( featureMatch = popupFeaturesRegex.exec(onclickMatch[2]) )) {
                        // Some values should remain numbers (#7300)
                        if (( featureMatch[2] == 'yes' || featureMatch[2] == '1' ) && !( featureMatch[1] in {
                                height: 1,
                                width: 1,
                                top: 1,
                                left: 1
                            } ))
                            retval.target[featureMatch[1]] = true;
                        else if (isFinite(featureMatch[2]))
                            retval.target[featureMatch[1]] = featureMatch[2];
                    }
                }
            }
            else {
                var targetMatch = target.match(selectableTargets);
                if (targetMatch)
                    retval.target.type = retval.target.name = target;
                else {
                    retval.target.type = 'frame';
                    retval.target.name = target;
                }
            }

            var me = this;
            var advAttr = function (inputName, attrName) {
                var value = element.getAttribute(attrName);
                if (value !== null)
                    retval.adv[inputName] = value || '';
            };
            advAttr('advId', 'id');
            advAttr('advLangDir', 'dir');
            advAttr('advAccessKey', 'accessKey');

            retval.adv.advName =
                element.data('cke-saved-name')
                || element.getAttribute('name')
                || '';
            advAttr('advLangCode', 'lang');
            advAttr('advTabIndex', 'tabindex');
            advAttr('advTitle', 'title');
            advAttr('advContentType', 'type');
            CKEDITOR.plugins.link.synAnchorSelector ?
                retval.adv.advCSSClasses = getLinkClass(element)
                : advAttr('advCSSClasses', 'class');
            advAttr('advCharset', 'charset');
            advAttr('advStyles', 'style');
            advAttr('advRel', 'rel');
        }

        // Find out whether we have any anchors in the editor.
        var anchors = retval.anchors = [],
            i, count, item;

        // For some browsers we set contenteditable="false" on anchors, making document.anchors not to include them, so we must traverse the links manually (#7893).
        if (CKEDITOR.plugins.link.emptyAnchorFix) {
            var links = editor.document.getElementsByTag('a');
            for (i = 0, count = links.count(); i < count; i++) {
                item = links.getItem(i);
                if (item.data('cke-saved-name') || item.hasAttribute('name'))
                    anchors.push({
                        name: item.data('cke-saved-name') || item.getAttribute('name'),
                        id: item.getAttribute('id')
                    });
            }
        }
        else {
            var anchorList = new CKEDITOR.dom.nodeList(editor.document.$.anchors);
            for (i = 0, count = anchorList.count(); i < count; i++) {
                item = anchorList.getItem(i);
                anchors[i] = {name: item.getAttribute('name'), id: item.getAttribute('id')};
            }
        }

        if (CKEDITOR.plugins.link.fakeAnchor) {
            var imgs = editor.document.getElementsByTag('img');
            for (i = 0, count = imgs.count(); i < count; i++) {
                if (( item = CKEDITOR.plugins.link.tryRestoreFakeAnchor(editor, imgs.getItem(i)) ))
                    anchors.push({name: item.getAttribute('name'), id: item.getAttribute('id')});
            }
        }

        // Record down the selected element in the dialog.
        this._.selectedElement = element;
        return retval;
    };

    var setupParams = function (page, data) {
        if (data[page])
            this.setValue(data[page][this.id] || '');
    };

    var setupPopupParams = function (data) {
        return setupParams.call(this, 'target', data);
    };

    var setupAdvParams = function (data) {
        return setupParams.call(this, 'adv', data);
    };

    var commitParams = function (page, data) {
        if (!data[page])
            data[page] = {};

        data[page][this.id] = this.getValue() || '';
    };

    var commitPopupParams = function (data) {
        return commitParams.call(this, 'target', data);
    };

    var commitAdvParams = function (data) {
        return commitParams.call(this, 'adv', data);
    };

    function unescapeSingleQuote(str) {
        return str.replace(/\\'/g, '\'');
    }

    function escapeSingleQuote(str) {
        return str.replace(/'/g, '\\$&');
    }

    var emailProtection = editor.config.emailProtection || '';

    // Compile the protection function pattern.
    if (emailProtection && emailProtection != 'encode') {
        var compiledProtectionFunction = {};

        emailProtection.replace(/^([^(]+)\(([^)]+)\)$/, function (match, funcName, params) {
            compiledProtectionFunction.name = funcName;
            compiledProtectionFunction.params = [];
            params.replace(/[^,\s]+/g, function (param) {
                compiledProtectionFunction.params.push(param);
            });
        });
    }

    function protectEmailLinkAsFunction(email) {
        var retval,
            name = compiledProtectionFunction.name,
            params = compiledProtectionFunction.params,
            paramName,
            paramValue;

        retval = [name, '('];
        for (var i = 0; i < params.length; i++) {
            paramName = params[i].toLowerCase();
            paramValue = email[paramName];

            i > 0 && retval.push(',');
            retval.push('\'',
                paramValue ?
                    escapeSingleQuote(encodeURIComponent(email[paramName]))
                    : '',
                '\'');
        }
        retval.push(')');
        return retval.join('');
    }

    function protectEmailAddressAsEncodedString(address) {
        var charCode,
            length = address.length,
            encodedChars = [];
        for (var i = 0; i < length; i++) {
            charCode = address.charCodeAt(i);
            encodedChars.push(charCode);
        }
        return 'String.fromCharCode(' + encodedChars.join(',') + ')';
    }

    function getLinkClass(ele) {
        var className = ele.getAttribute('class');
        return className ? className.replace(/\s*(?:cke_anchor_empty|cke_anchor)(?:\s*$)?/g, '') : '';
    }

    var commonLang = editor.lang.common,
        linkLang = editor.lang.link;

    return {
        title: linkLang.title,
        minWidth: 350,
        minHeight: 230,
        contents: [
            {
                id: 'info',
                label: linkLang.info,
                title: linkLang.info,
                elements: [
                    {
                        id: 'linkType',
                        type: 'select',
                        label: linkLang.type,
                        'default': 'url',
                        items: [
                            [linkLang.toUrl, 'url'],
                            [linkLang.toAnchor, 'anchor'],
                            [linkLang.toEmail, 'email']
                        ],
                        onChange: linkTypeChanged,
                        setup: function (data) {
                            if (data.type)
                                this.setValue(data.type);
                        },
                        commit: function (data) {
                            data.type = this.getValue();
                        }
                    },
                    {
                        type: 'text',
                        label: linkLang.advisoryTitle,
                        'default': '',
                        id: 'linkText',
                        setup: function (data) {
                            if (data.linkText)
                                this.setValue(data.linkText);
                        },
                        commit: function (data) {
                            data.linkText = this.getValue();
                        }
                    },
                    {
                        type: 'vbox',
                        id: 'urlOptions',
                        children: [
                            {
                                type: 'hbox',
                                widths: ['25%', '75%'],
                                children: [
                                    {
                                        id: 'protocol',
                                        type: 'select',
                                        label: commonLang.protocol,
                                        'default': 'http://',
                                        items: [
                                            // Force 'ltr' for protocol names in BIDI. (#5433)
                                            ['http://\u200E', 'http://'],
                                            ['https://\u200E', 'https://'],
                                            ['ftp://\u200E', 'ftp://'],
                                            ['news://\u200E', 'news://'],
                                            [linkLang.other, '']
                                        ],
                                        setup: function (data) {
                                            if (data.url)
                                                this.setValue(data.url.protocol || '');
                                        },
                                        commit: function (data) {
                                            if (!data.url)
                                                data.url = {};

                                            data.url.protocol = this.getValue();
                                        }
                                    },
                                    {
                                        type: 'text',
                                        id: 'url',
                                        label: commonLang.url,
                                        required: true,
                                        onLoad: function () {
                                            this.allowOnChange = true;
                                        },
                                        onKeyUp: function () {
                                            this.allowOnChange = false;
                                            var protocolCmb = this.getDialog().getContentElement('info', 'protocol'),
                                                url = this.getValue(),
                                                urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/i,
                                                urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/i;

                                            var protocol = urlOnChangeProtocol.exec(url);
                                            if (protocol) {
                                                this.setValue(url.substr(protocol[0].length));
                                                protocolCmb.setValue(protocol[0].toLowerCase());
                                            }
                                            else if (urlOnChangeTestOther.test(url))
                                                protocolCmb.setValue('');

                                            this.allowOnChange = true;
                                        },
                                        onChange: function () {
                                            if (this.allowOnChange)		// Dont't call on dialog load.
                                                this.onKeyUp();
                                        },
                                        validate: function () {
                                            var dialog = this.getDialog();

                                            if (dialog.getContentElement('info', 'linkType') &&
                                                dialog.getValueOf('info', 'linkType') != 'url')
                                                return true;

                                            if (this.getDialog().fakeObj)	// Edit Anchor.
                                                return true;

                                            var func = CKEDITOR.dialog.validate.notEmpty(linkLang.noUrl);
                                            return func.apply(this);
                                        },
                                        setup: function (data) {
                                            this.allowOnChange = false;
                                            if (data.url)
                                                this.setValue(data.url.url);
                                            this.allowOnChange = true;

                                        },
                                        commit: function (data) {
                                            // IE will not trigger the onChange event if the mouse has been used
                                            // to carry all the operations #4724
                                            this.onChange();

                                            if (!data.url)
                                                data.url = {};

                                            data.url.url = this.getValue();
                                            this.allowOnChange = false;
                                        }
                                    }
                                ],
                                setup: function (data) {
                                    if (!this.getDialog().getContentElement('info', 'linkType'))
                                        this.getElement().show();
                                }
                            },
                            {
                                type: 'button',
                                id: 'browse',
                                hidden: 'true',
                                filebrowser: 'info:url',
                                label: commonLang.browseServer
                            }
                        ]
                    },
                    {
                        type: 'vbox',
                        id: 'anchorOptions',
                        width: 260,
                        align: 'center',
                        padding: 0,
                        children: [
                            {
                                type: 'fieldset',
                                id: 'selectAnchorText',
                                label: linkLang.selectAnchor,
                                setup: function (data) {
                                    if (data.anchors.length > 0)
                                        this.getElement().show();
                                    else
                                        this.getElement().hide();
                                },
                                children: [
                                    {
                                        type: 'hbox',
                                        id: 'selectAnchor',
                                        children: [
                                            {
                                                type: 'select',
                                                id: 'anchorName',
                                                'default': '',
                                                label: linkLang.anchorName,
                                                style: 'width: 100%;',
                                                items: [
                                                    ['']
                                                ],
                                                setup: function (data) {
                                                    this.clear();
                                                    this.add('');
                                                    for (var i = 0; i < data.anchors.length; i++) {
                                                        if (data.anchors[i].name)
                                                            this.add(data.anchors[i].name);
                                                    }

                                                    if (data.anchor)
                                                        this.setValue(data.anchor.name);

                                                    var linkType = this.getDialog().getContentElement('info', 'linkType');
                                                    if (linkType && linkType.getValue() == 'email')
                                                        this.focus();
                                                },
                                                commit: function (data) {
                                                    if (!data.anchor)
                                                        data.anchor = {};

                                                    data.anchor.name = this.getValue();
                                                }
                                            },
                                            {
                                                type: 'select',
                                                id: 'anchorId',
                                                'default': '',
                                                label: linkLang.anchorId,
                                                style: 'width: 100%;',
                                                items: [
                                                    ['']
                                                ],
                                                setup: function (data) {
                                                    this.clear();
                                                    this.add('');
                                                    for (var i = 0; i < data.anchors.length; i++) {
                                                        if (data.anchors[i].id)
                                                            this.add(data.anchors[i].id);
                                                    }

                                                    if (data.anchor)
                                                        this.setValue(data.anchor.id);
                                                },
                                                commit: function (data) {
                                                    if (!data.anchor)
                                                        data.anchor = {};

                                                    data.anchor.id = this.getValue();
                                                }
                                            }
                                        ],
                                        setup: function (data) {
                                            if (data.anchors.length > 0)
                                                this.getElement().show();
                                            else
                                                this.getElement().hide();
                                        }
                                    }
                                ]
                            },
                            {
                                type: 'html',
                                id: 'noAnchors',
                                style: 'text-align: center;',
                                html: '<div role="note" tabIndex="-1">' + CKEDITOR.tools.htmlEncode(linkLang.noAnchors) + '</div>',
                                // Focus the first element defined in above html.
                                focus: true,
                                setup: function (data) {
                                    if (data.anchors.length < 1)
                                        this.getElement().show();
                                    else
                                        this.getElement().hide();
                                }
                            }
                        ],
                        setup: function (data) {
                            if (!this.getDialog().getContentElement('info', 'linkType'))
                                this.getElement().hide();
                        }
                    },
                    {
                        type: 'vbox',
                        id: 'emailOptions',
                        padding: 1,
                        children: [
                            {
                                type: 'text',
                                id: 'emailAddress',
                                label: linkLang.emailAddress,
                                required: true,
                                validate: function () {
                                    var dialog = this.getDialog();

                                    if (!dialog.getContentElement('info', 'linkType') ||
                                        dialog.getValueOf('info', 'linkType') != 'email')
                                        return true;

                                    var func = CKEDITOR.dialog.validate.notEmpty(linkLang.noEmail);
                                    return func.apply(this);
                                },
                                setup: function (data) {
                                    if (data.email)
                                        this.setValue(data.email.address);

                                    var linkType = this.getDialog().getContentElement('info', 'linkType');
                                    if (linkType && linkType.getValue() == 'email')
                                        this.select();
                                },
                                commit: function (data) {
                                    if (!data.email)
                                        data.email = {};

                                    data.email.address = this.getValue();
                                }
                            },
                            {
                                type: 'text',
                                id: 'emailSubject',
                                label: linkLang.emailSubject,
                                setup: function (data) {
                                    if (data.email)
                                        this.setValue(data.email.subject);
                                },
                                commit: function (data) {
                                    if (!data.email)
                                        data.email = {};

                                    data.email.subject = this.getValue();
                                }
                            },
                            {
                                type: 'textarea',
                                id: 'emailBody',
                                label: linkLang.emailBody,
                                rows: 3,
                                'default': '',
                                setup: function (data) {
                                    if (data.email)
                                        this.setValue(data.email.body);
                                },
                                commit: function (data) {
                                    if (!data.email)
                                        data.email = {};

                                    data.email.body = this.getValue();
                                }
                            }
                        ],
                        setup: function (data) {
                            if (!this.getDialog().getContentElement('info', 'linkType'))
                                this.getElement().hide();
                        }
                    }
                ]
            },
            {
                id: 'target',
                label: linkLang.target,
                title: linkLang.target,
                elements: [
                    {
                        type: 'hbox',
                        widths: ['50%', '50%'],
                        children: [
                            {
                                type: 'select',
                                id: 'linkTargetType',
                                label: commonLang.target,
                                'default': 'notSet',
                                style: 'width : 100%;',
                                'items': [
                                    [commonLang.notSet, 'notSet'],
                                    [linkLang.targetFrame, 'frame'],
                                    [linkLang.targetPopup, 'popup'],
                                    [commonLang.targetNew, '_blank'],
                                    [commonLang.targetTop, '_top'],
                                    [commonLang.targetSelf, '_self'],
                                    [commonLang.targetParent, '_parent']
                                ],
                                onChange: targetChanged,
                                setup: function (data) {
                                    if (data.target)
                                        this.setValue(data.target.type || 'notSet');
                                    targetChanged.call(this);
                                },
                                commit: function (data) {
                                    if (!data.target)
                                        data.target = {};

                                    data.target.type = this.getValue();
                                }
                            },
                            {
                                type: 'text',
                                id: 'linkTargetName',
                                label: linkLang.targetFrameName,
                                'default': '',
                                setup: function (data) {
                                    if (data.target)
                                        this.setValue(data.target.name);
                                },
                                commit: function (data) {
                                    if (!data.target)
                                        data.target = {};

                                    data.target.name = this.getValue().replace(/\W/gi, '');
                                }
                            }
                        ]
                    },
                    {
                        type: 'vbox',
                        width: '100%',
                        align: 'center',
                        padding: 2,
                        id: 'popupFeatures',
                        children: [
                            {
                                type: 'fieldset',
                                label: linkLang.popupFeatures,
                                children: [
                                    {
                                        type: 'hbox',
                                        children: [
                                            {
                                                type: 'checkbox',
                                                id: 'resizable',
                                                label: linkLang.popupResizable,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams
                                            },
                                            {
                                                type: 'checkbox',
                                                id: 'status',
                                                label: linkLang.popupStatusBar,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            }
                                        ]
                                    },
                                    {
                                        type: 'hbox',
                                        children: [
                                            {
                                                type: 'checkbox',
                                                id: 'location',
                                                label: linkLang.popupLocationBar,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            },
                                            {
                                                type: 'checkbox',
                                                id: 'toolbar',
                                                label: linkLang.popupToolbar,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            }
                                        ]
                                    },
                                    {
                                        type: 'hbox',
                                        children: [
                                            {
                                                type: 'checkbox',
                                                id: 'menubar',
                                                label: linkLang.popupMenuBar,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            },
                                            {
                                                type: 'checkbox',
                                                id: 'fullscreen',
                                                label: linkLang.popupFullScreen,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            }
                                        ]
                                    },
                                    {
                                        type: 'hbox',
                                        children: [
                                            {
                                                type: 'checkbox',
                                                id: 'scrollbars',
                                                label: linkLang.popupScrollBars,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            },
                                            {
                                                type: 'checkbox',
                                                id: 'dependent',
                                                label: linkLang.popupDependent,
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            }
                                        ]
                                    },
                                    {
                                        type: 'hbox',
                                        children: [
                                            {
                                                type: 'text',
                                                widths: ['50%', '50%'],
                                                labelLayout: 'horizontal',
                                                label: commonLang.width,
                                                id: 'width',
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            },
                                            {
                                                type: 'text',
                                                labelLayout: 'horizontal',
                                                widths: ['50%', '50%'],
                                                label: linkLang.popupLeft,
                                                id: 'left',
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            }
                                        ]
                                    },
                                    {
                                        type: 'hbox',
                                        children: [
                                            {
                                                type: 'text',
                                                labelLayout: 'horizontal',
                                                widths: ['50%', '50%'],
                                                label: commonLang.height,
                                                id: 'height',
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            },
                                            {
                                                type: 'text',
                                                labelLayout: 'horizontal',
                                                label: linkLang.popupTop,
                                                widths: ['50%', '50%'],
                                                id: 'top',
                                                setup: setupPopupParams,
                                                commit: commitPopupParams

                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            },
            {
                id: 'upload',
                label: linkLang.upload,
                title: linkLang.upload,
                hidden: true,
                filebrowser: 'uploadButton',
                elements: [
                    {
                        type: 'file',
                        id: 'upload',
                        label: commonLang.upload,
                        style: 'height:40px',
                        size: 29
                    },
                    {
                        type: 'fileButton',
                        id: 'uploadButton',
                        label: commonLang.uploadSubmit,
                        filebrowser: 'info:url',
                        'for': ['upload', 'upload']
                    }
                ]
            },
            {
                id: 'advanced',
                label: linkLang.advanced,
                title: linkLang.advanced,
                elements: [
                    {
                        type: 'vbox',
                        padding: 1,
                        children: [
                            {
                                type: 'hbox',
                                widths: ['45%', '35%', '20%'],
                                children: [
                                    {
                                        type: 'text',
                                        id: 'advId',
                                        label: linkLang.id,
                                        setup: setupAdvParams,
                                        commit: commitAdvParams
                                    },
                                    {
                                        type: 'select',
                                        id: 'advLangDir',
                                        label: linkLang.langDir,
                                        'default': '',
                                        style: 'width:110px',
                                        items: [
                                            [commonLang.notSet, ''],
                                            [linkLang.langDirLTR, 'ltr'],
                                            [linkLang.langDirRTL, 'rtl']
                                        ],
                                        setup: setupAdvParams,
                                        commit: commitAdvParams
                                    },
                                    {
                                        type: 'text',
                                        id: 'advAccessKey',
                                        width: '80px',
                                        label: linkLang.acccessKey,
                                        maxLength: 1,
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    }
                                ]
                            },
                            {
                                type: 'hbox',
                                widths: ['45%', '35%', '20%'],
                                children: [
                                    {
                                        type: 'text',
                                        label: linkLang.name,
                                        id: 'advName',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    },
                                    {
                                        type: 'text',
                                        label: linkLang.langCode,
                                        id: 'advLangCode',
                                        width: '110px',
                                        'default': '',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    },
                                    {
                                        type: 'text',
                                        label: linkLang.tabIndex,
                                        id: 'advTabIndex',
                                        width: '80px',
                                        maxLength: 5,
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    }
                                ]
                            }
                        ]
                    },
                    {
                        type: 'vbox',
                        padding: 1,
                        children: [
                            {
                                type: 'hbox',
                                widths: ['45%', '55%'],
                                children: [
                                    {
                                        type: 'text',
                                        label: linkLang.advisoryTitle,
                                        'default': '',
                                        id: 'advTitle',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    },
                                    {
                                        type: 'text',
                                        label: linkLang.advisoryContentType,
                                        'default': '',
                                        id: 'advContentType',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    }
                                ]
                            },
                            {
                                type: 'hbox',
                                widths: ['45%', '55%'],
                                children: [
                                    {
                                        type: 'text',
                                        label: linkLang.cssClasses,
                                        'default': '',
                                        id: 'advCSSClasses',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    },
                                    {
                                        type: 'text',
                                        label: linkLang.charset,
                                        'default': '',
                                        id: 'advCharset',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams

                                    }
                                ]
                            },
                            {
                                type: 'hbox',
                                widths: ['45%', '55%'],
                                children: [
                                    {
                                        type: 'text',
                                        label: linkLang.rel,
                                        'default': '',
                                        id: 'advRel',
                                        setup: setupAdvParams,
                                        commit: commitAdvParams
                                    },
                                    {
                                        type: 'text',
                                        label: linkLang.styles,
                                        'default': '',
                                        id: 'advStyles',
                                        validate: CKEDITOR.dialog.validate.inlineStyle(editor.lang.common.invalidInlineStyle),
                                        setup: setupAdvParams,
                                        commit: commitAdvParams
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ],
        onShow: function () {
            var editor = this.getParentEditor(),
                selection = editor.getSelection(),
                element = null;

            // Fill in all the relevant fields if there's already one link selected.
            if (( element = plugin.getSelectedLink(editor) ) && element.hasAttribute('href'))
                selection.selectElement(element);
            else
                element = null;

            this.setupContent(parseLink.apply(this, [editor, element]));
        },
        onOk: function () {
            var attributes = {},
                removeAttributes = [],
                data = {},
                me = this,
                editor = this.getParentEditor();

            this.commitContent(data);

            // Compose the URL.
            switch (data.type || 'url') {
                case 'url':
                    var protocol = ( data.url && data.url.protocol != undefined ) ? data.url.protocol : 'http://',
                        url = ( data.url && CKEDITOR.tools.trim(data.url.url) ) || '';
                    attributes['data-cke-saved-href'] = ( url.indexOf('/') === 0 ) ? url : protocol + url;
                    break;
                case 'anchor':
                    var name = ( data.anchor && data.anchor.name ),
                        id = ( data.anchor && data.anchor.id );
                    attributes['data-cke-saved-href'] = '#' + ( name || id || '' );
                    break;
                case 'email':

                    var linkHref,
                        email = data.email,
                        address = email.address;

                    switch (emailProtection) {
                        case '' :
                        case 'encode' :
                        {
                            var subject = encodeURIComponent(email.subject || ''),
                                body = encodeURIComponent(email.body || '');

                            // Build the e-mail parameters first.
                            var argList = [];
                            subject && argList.push('subject=' + subject);
                            body && argList.push('body=' + body);
                            argList = argList.length ? '?' + argList.join('&') : '';

                            if (emailProtection == 'encode') {
                                linkHref = ['javascript:void(location.href=\'mailto:\'+',
                                    protectEmailAddressAsEncodedString(address)];
                                // parameters are optional.
                                argList && linkHref.push('+\'', escapeSingleQuote(argList), '\'');

                                linkHref.push(')');
                            }
                            else
                                linkHref = ['mailto:', address, argList];

                            break;
                        }
                        default :
                        {
                            // Separating name and domain.
                            var nameAndDomain = address.split('@', 2);
                            email.name = nameAndDomain[0];
                            email.domain = nameAndDomain[1];

                            linkHref = ['javascript:', protectEmailLinkAsFunction(email)];
                        }
                    }

                    attributes['data-cke-saved-href'] = linkHref.join('');
                    break;
            }

            // Popups and target.
            if (data.target) {
                if (data.target.type == 'popup') {
                    var onclickList = ['window.open(this.href, \'',
                        data.target.name || '', '\', \''];
                    var featureList = ['resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen',
                        'scrollbars', 'dependent'];
                    var featureLength = featureList.length;
                    var addFeature = function (featureName) {
                        if (data.target[featureName])
                            featureList.push(featureName + '=' + data.target[featureName]);
                    };

                    for (var i = 0; i < featureLength; i++)
                        featureList[i] = featureList[i] + ( data.target[featureList[i]] ? '=yes' : '=no' );
                    addFeature('width');
                    addFeature('left');
                    addFeature('height');
                    addFeature('top');

                    onclickList.push(featureList.join(','), '\'); return false;');
                    attributes['data-cke-pa-onclick'] = onclickList.join('');

                    // Add the "target" attribute. (#5074)
                    removeAttributes.push('target');
                }
                else {
                    if (data.target.type != 'notSet' && data.target.name)
                        attributes.target = data.target.name;
                    else
                        removeAttributes.push('target');

                    removeAttributes.push('data-cke-pa-onclick', 'onclick');
                }
            }

            // Advanced attributes.
            if (data.adv) {
                var advAttr = function (inputName, attrName) {
                    var value = data.adv[inputName];
                    if (value)
                        attributes[attrName] = value;
                    else
                        removeAttributes.push(attrName);
                };

                advAttr('advId', 'id');
                advAttr('advLangDir', 'dir');
                advAttr('advAccessKey', 'accessKey');

                if (data.adv['advName'])
                    attributes['name'] = attributes['data-cke-saved-name'] = data.adv['advName'];
                else
                    removeAttributes = removeAttributes.concat(['data-cke-saved-name', 'name']);

                advAttr('advLangCode', 'lang');
                advAttr('advTabIndex', 'tabindex');
                advAttr('advTitle', 'title');
                advAttr('advContentType', 'type');
                advAttr('advCSSClasses', 'class');
                advAttr('advCharset', 'charset');
                advAttr('advStyles', 'style');
                advAttr('advRel', 'rel');
            }


            var selection = editor.getSelection();

            // Browser need the "href" fro copy/paste link to work. (#6641)
            attributes.href = attributes['data-cke-saved-href'];

            if (!this._.selectedElement) {
                // Create element if current selection is collapsed.
                var ranges = selection.getRanges(true);
                if (ranges.length == 1 && ranges[0].collapsed) {
                    // Short mailto link text view (#5736).
                    var text = new CKEDITOR.dom.text(data.type == 'email' ?
                        data.email.address : attributes['data-cke-saved-href'], editor.document);
                    if (data.linkText != '') {
                        text.setText(data.linkText);
                    } else {
                        var h = attributes['data-cke-saved-href'];
                        text.setText(decodeURIComponent(h.substring(h.lastIndexOf("/") + 1)));
                    }
                    ranges[0].insertNode(text);
                    ranges[0].selectNodeContents(text);
                    selection.selectRanges(ranges);
                }

                // Apply style.
                var style = new CKEDITOR.style({element: 'a', attributes: attributes});
                style.type = CKEDITOR.STYLE_INLINE;		// need to override... dunno why.
                style.apply(editor.document);
            }
            else {
                // We're only editing an existing link, so just overwrite the attributes.
                var element = this._.selectedElement,
                    href = element.data('cke-saved-href'),
                    textView = element.getHtml();

                element.setAttributes(attributes);
                element.removeAttributes(removeAttributes);

                if (data.adv && data.adv.advName && CKEDITOR.plugins.link.synAnchorSelector)
                    element.addClass(element.getChildCount() ? 'cke_anchor' : 'cke_anchor_empty');

                // Update text view when user changes protocol (#4612).
                if (href == textView || data.type == 'email' && textView.indexOf('@') != -1) {
                    // Short mailto link text view (#5736).
                    element.setHtml(data.type == 'email' ?
                        data.email.address : attributes['data-cke-saved-href']);
                }

                selection.selectElement(element);
                delete this._.selectedElement;
            }
        },
        onLoad: function () {
            if (!editor.config.linkShowAdvancedTab)
                this.hidePage('advanced');		//Hide Advanded tab.

            if (!editor.config.linkShowTargetTab)
                this.hidePage('target');		//Hide Target tab.

        },
        // Inital focus on 'url' field if link is of type URL.
        onFocus: function () {
            var linkType = this.getContentElement('info', 'linkType'),
                urlField;
            if (linkType && linkType.getValue() == 'url') {
                urlField = this.getContentElement('info', 'url');
                urlField.select();
            }
        }
    };
});

/**
 * The e-mail address anti-spam protection option. The protection will be
 * applied when creating or modifying e-mail links through the editor interface.<br>
 * Two methods of protection can be choosed:
 * <ol>    <li>The e-mail parts (name, domain and any other query string) are
 *            assembled into a function call pattern. Such function must be
 *            provided by the developer in the pages that will use the contents.
 *        <li>Only the e-mail address is obfuscated into a special string that
 *            has no meaning for humans or spam bots, but which is properly
 *            rendered and accepted by the browser.</li></ol>
 * Both approaches require JavaScript to be enabled.
 * @name CKEDITOR.config.emailProtection
 * @since 3.1
 * @type String
 * @default '' (empty string = disabled)
 * @example
 * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
 * config.emailProtection = '';
 * @example
 * // href="<a href=\"javascript:void(location.href=\'mailto:\'+String.fromCharCode(116,101,115,116,101,114,64,99,107,101,100,105,116,111,114,46,99,111,109)+\'?subject=subject&body=body\')\">e-mail</a>"
 * config.emailProtection = 'encode';
 * @example
 * // href="javascript:mt('tester','ckeditor.com','subject','body')"
 * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
 */
